package com.lagou.rpc.config;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @param
 * @author oyz
 * @version 1.0
 * @description: TODO 用于扫描被@RpcService注解的bean缓存
 * @date 2022/2/28 14:34
 */
public class ImportRpcBeanHandler {
    /**
     * 定义一个集合用来保存实现类包名数组
     */
    private static List<String> providerList = new ArrayList<>();


    /**
     * 用来装服务提供者的实例,相当于bean容器
      */
    private static Map<String, Object> instanceCacheMap = new ConcurrentHashMap<>();


    static {
        // 加载com.lagou.rpc.provider.service 拿到里边被注解的实现类
        loadProviderInstance("com.lagou.rpc.provider.service");
    }

    /**
     * @description: TODO 扫描service包下的实现类，并把他放入缓存
     * @author oyz
     * @param packageName 包路径名
     * @date 2022/2/28 14:37
     * @version 1.0
     */
    private static void loadProviderInstance( String packageName) {
        findProviderClass(packageName);
        putProviderInstance();
    }
    /**
     * @description: 并依次将实现类的接口作为key，实现类的实例作为值放入instanceCacheMap集合中,其实这里也是模拟服务注册的过程
     * 注意这里没有处理一个接口有多个实现类的情况(针对一个接口只存在一个实现类)
     * @author oyz
     * @param
     * @date 2022/2/28 15:11
     * @version 1.0
     */
    private static void putProviderInstance() {
        for (String providerName : providerList) {
            // 通过反射生成实例对象
            try{
                Class<?> aClass = Class.forName(providerName);
                Class<?>[] interfaces = aClass.getInterfaces();
                if (null == interfaces || interfaces.length <=0){
                    throw new RuntimeException("该实现类没有实现接口");
                }
                // 得到类名
                String name = interfaces[0].getName();
                // 得到实例对象
                Object o = aClass.newInstance();
                instanceCacheMap.put(name,o);
                System.out.println("需要注册"+ name + "的服务");
            }catch (Exception e){
                e.printStackTrace();
            }
        }


    }

    /**
     * @description: TODO 获取实现类的路径
     * @author oyz
     * @param packageName
     * @date 2022/2/28 15:10
     * @version 1.0
     */
    private static void findProviderClass(final String packageName) {
        // 所以得用匿名内部类来解决
        // 这里由classLoader的getResource方法获得包名并封装成URL形式
        URL url = new Object(){

            public URL getPath() {
                String packageDir = packageName.replace(".", "/");
                // 由类加载器获得该实例对象
                URL url1 = this.getClass().getClassLoader().getResource(packageDir);
                return url1;
            }
        }.getPath();
        // 将包名转换为file格式,判断是文件还是文件夹,如果是文件加就递归该方法
        // 如果是文件，就把实现类的名字放入数组进行存储
        File file = new File(url.getFile());
        File[] files = file.listFiles();
        for(File dir: files){
            // 是文件夹继续递归
            if(dir.isDirectory()){
                findProviderClass(packageName+"."+dir.getName());
            }else{
                providerList.add(packageName+"."+dir.getName().replace(".class",""));
            }
        }

    }


    public static Map<String, Object> getInstanceCacheMap(){
        return instanceCacheMap;
    }


}
